use crate::ast::{
   AstBinaryOperator, AstBinaryOperatorKind, AstExpression, AstExpressionKind,
   AstNumberExpression, AstStatement, AstUnaryOperator, AstUnaryOperatorKind,
   OperatorPrecedence,
};
use crate::lexer::Lexer;
use crate::token::{Token, TokenKind};

use std::cell::Cell;

#[derive(Debug, Clone)]
pub struct Counter {
   value: Cell<usize>,
}

impl Counter {
   pub fn new() -> Self {
      Self {
         value: Cell::new(0),
      }
   }

   pub fn increment(&self) {
      let current_value = self.value.get();
      self.value.set(current_value + 1);
   }

   pub fn get_value(&self) -> usize {
      self.value.get()
   }
}

pub struct Parser {
   tokens: Vec<Token>,
   pos: Counter,
}

impl Parser {
   pub fn new() -> Self {
      Self {
         tokens: Vec::new(),
         pos: Counter::new(),
      }
   }

   pub fn from_input(input: &str) -> Self {
      let mut lexer = Lexer::new(input);
      let mut tokens = Vec::new();
      while let Some(token) = lexer.next_token() {
         tokens.push(token);
      }
      Self {
         tokens,
         pos: Counter::new(),
      }
   }

   pub fn parse(&mut self) -> Option<AstStatement> {
      self.parse_statement()
   }

   fn parse_statement(&mut self) -> Option<AstStatement> {
      if self.current().kind == TokenKind::Eof {
         return None;
      }
      let expr = self.parse_expression()?;
      Some(AstStatement::expression(expr))
   }

   fn parse_expression(&mut self) -> Option<AstExpression> {
      self.parse_binary_expression(OperatorPrecedence::Lowest)
   }

   fn parse_binary_expression(
      &mut self,
      precedence: OperatorPrecedence,
   ) -> Option<AstExpression> {
      let mut left = self.parse_unary_expression()?;

      while let Some(operator) = self.parse_binary_operator() {
         // 获取优先级
         let operator_precedence = operator.precedence();

         // 优先级判断
         if operator_precedence < precedence {
            break;
         }
         self.consume();

         let right = self.parse_binary_expression(operator_precedence);
         left = AstExpression::binary(operator, left, right?);
      }

      Some(left)
   }
   fn parse_binary_operator(&mut self) -> Option<AstBinaryOperator> {
      use TokenKind::*;
      let token = self.current();
      let kind = match token.kind {
         Plus => Some(AstBinaryOperatorKind::Plus), // Add
         Minus => Some(AstBinaryOperatorKind::Minus), // Subtract
         Asterisk => Some(AstBinaryOperatorKind::Multiply), // Multiply
         Slash => Some(AstBinaryOperatorKind::Divide), // Divide
         Caret => Some(AstBinaryOperatorKind::Power), // Caret
         _ => None,
      };

      kind.map(|kind| AstBinaryOperator::new(kind, token.clone()))
   }

   fn parse_unary_expression(&mut self) -> Option<AstExpression> {
      if let Some(operator) = self.parse_unary_opreator() {
         self.consume();
         // 获取到操作数
         let opreand = self.parse_unary_expression().unwrap();
         // 传递负号和操作数
         return Some(AstExpression::unary(operator, opreand));
      }
      self.parse_primary_expression()
   }

   fn parse_unary_opreator(&mut self) -> Option<AstUnaryOperator> {
      let token = self.current();

      let kind = match token.kind {
         TokenKind::Minus => Some(AstUnaryOperatorKind::Minus), // 负号 -
         _ => None,
      };

      kind.map(|kind| AstUnaryOperator::new(kind, token.clone()))
   }

   fn parse_primary_expression(&mut self) -> Option<AstExpression> {
      let token = self.consume();
      match token.kind {
         TokenKind::NumberInt(_int_number) => {
            // eprintln!("int number: {int_number:?}");
            let number = token.lexeme.parse().unwrap();
            Some(AstExpression::number(AstExpressionKind::NumberInt(
               AstNumberExpression::new(number),
            )))
         }
         TokenKind::NumberFloat(_float_number) => {
            // eprintln!("float number: {float_number:?}");
            let number = token.lexeme.parse().unwrap();
            Some(AstExpression::number(AstExpressionKind::NumberFloat(
               AstNumberExpression::new(number),
            )))
         }
         TokenKind::LParen => {
            // eprintln!("() expression");
            let expr = self.parse_expression()?;
            self.consume_and_check(TokenKind::RParen);
            Some(AstExpression::parenthesized(expr))
         }
         _ => None,
      }
   }

   pub fn peek(&self, offset: isize) -> Token {
      let mut index = (self.pos.get_value() as isize + offset) as usize;
      if index >= self.tokens.len() {
         index = self.tokens.len() - 1;
      }
      self.tokens[index].clone()
   }

   fn current(&self) -> Token {
      self.peek(0)
   }

   fn consume(&mut self) -> Token {
      self.pos.increment();
      self.peek(-1)
   }

   fn consume_and_check(&mut self, kind: TokenKind) -> Token {
      let token = self.consume();
      if token.kind != kind {
         panic!("xxxxxxxx  error xxxxx");
      }
      token
   }
}
